package sm.hibernate.loader;

import java.util.Map;

import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.loader.collection.BasicCollectionJoinWalker;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.sql.DisjunctionFragment;
import org.hibernate.sql.InFragment;
import org.hibernate.util.StringHelper;

import sm.hibernate.sql.SMConditionFragment;

public class SMCollectionJoinWalker extends BasicCollectionJoinWalker {
	public SMCollectionJoinWalker(QueryableCollection collectionPersister,
			int batchSize, String subquery, SessionFactoryImplementor factory,
			Map enabledFilters) {
		super(collectionPersister, batchSize, subquery, factory, enabledFilters);
	}

	@Override
	protected StringBuffer whereString(String alias, String[] columnNames,
			String subselect, int batchSize) {
		if (subselect == null) {
			return whereString(alias, columnNames, batchSize);
		} else {
			StringBuffer buf = new StringBuffer();
			if (columnNames.length > 1)
				buf.append('(');
			buf.append(StringHelper.join(", ",
					StringHelper.qualify(alias, columnNames)));
			if (columnNames.length > 1)
				buf.append(')');
			buf.append(" in ").append('(').append(subselect).append(')');
			return buf;
		}
	}

	@Override
	protected StringBuffer whereString(String alias, String[] columnNames,
			int batchSize) {
		if (columnNames.length == 1) {
			// if not a composite key, use "foo in (?, ?, ?)" for batching
			// if no batch, and not a composite key, use "foo = ?"
			InFragment in = new InFragment().setColumn(alias, columnNames[0]);
			for (int i = 0; i < batchSize; i++)
				in.addValue("?");
			return new StringBuffer(in.toFragmentString());
		} else {
			// a composite key
			// customize: use SMConditionFragment
			SMConditionFragment byId = new SMConditionFragment().setTableAlias(
					alias).setCondition(columnNames, "?");

			StringBuffer whereString = new StringBuffer();
			if (batchSize == 1) {
				// if no batch, use "foo = ? and bar = ?"
				whereString.append(byId.toFragmentString());
			} else {
				// if a composite key, use
				// "( (foo = ? and bar = ?) or (foo = ? and bar = ?) )" for
				// batching
				whereString.append('('); // TODO: unnecessary for databases with
											// ANSI-style joins
				DisjunctionFragment df = new DisjunctionFragment();
				for (int i = 0; i < batchSize; i++) {
					df.addCondition(byId);
				}
				whereString.append(df.toFragmentString());
				whereString.append(')'); // TODO: unnecessary for databases with
											// ANSI-style joins
			}
			return whereString;
		}
	}
}
